import os
import re
import chardet
import TrosParser.libs.config as config

class signal():
    def __init__(self):
        self.name = ''
        self.len = 0
        self.start_bit = 0
        self.factor = 0
        self.offset = 0
        self.max = 0
        self.min = 0
        self.signal_type = ''
        self.endian = 'BIG_ENDIAN'
        
class message():
    def __init__(self):
        self.name = ''
        self.can_node = ''
        self.signals = []
        self.direction = ''
        self.dlc = 0
        self.id = 0
        self.swc = ''

class dbcs_parser():
    def __init__(self):
        self.files = []
        self.data = []
        self.config = ''
    
    def parse_config(self):
        self.config = config.config()
        self.config.read_json_file()

    def find_dbc_files(self, directorys):
        # 用于存储找到的.a2l文件的路径
        dbc_files = []
        directory_list = directorys.split(" ")
        for directory in directory_list:
            # 遍历目录和子目录
            for root, _, files in os.walk(directory):
                for file in files:
                    if file.endswith('.dbc'):
                        dbc_files.append(os.path.join(root, file))               
        return dbc_files

    def read_dbcs(self, dbc_files, logging):
        message_id_list = []
        
        """
        NodesPattern:节点
        MessagePattern：消息
        SignalPattern：信号
        """
        NodesPattern = re.compile(r"BU_: (.*)", re.S)
        MessagePattern = re.compile(r"BO_ (.*?) (.*?): (.*?) (.*)", re.S)
        SignalPattern = re.compile('''SG_ (.*?) : (.*?)\|(.*?)@(.*?)([+-]) \((.*?),(.*?)\) \[(.*?)\|(.*?)\] "(.*?)" (.*)''', re.S)
        line = ''

        for file in dbc_files:
            rawdata = open(file, 'rb').read()
            result = chardet.detect(rawdata)
            encoding = result['encoding']
            can_node_list = self.config.can_node_list
            
            for item in can_node_list:
                if item['file_name'] == file.split('/')[-1].split('.dbc')[0]:
                    t_cannode = item['node_name']
                    break
            if t_cannode == '':
                logging.error("请检查json文件中dbc名称！")
            f = open(file, "r",encoding=encoding)
            lines = f.readlines()
            f.seek(0)
                            
            for t_line in lines:
                if t_line.find("BO_TX_BU_") >=0:
                    if t_line.split(" ")[-1].find(self.config.local_node) >= 0:
                        message_id_list.append(t_line.split(" ")[1])
            i = 0
            while i < len(lines)-1:
                line = lines[i]
                if line.strip() != '' and line.strip()[0] == '"':
                    lines[i-1] += line
                    lines.remove(line)
                    i -= 1
                i += 1

            f.close()
            index = 0
            line = lines[index]
            while line:
                NodesSearched = re.search(NodesPattern, line.strip())
                if NodesSearched:
                    node = NodesSearched.group(1).split(" ")
                    #print(node)
                MessageSearched = re.search(MessagePattern, line.strip())
                if MessageSearched:
                    t_message = message()
                    Message = list(MessageSearched.groups())
                    t_message.id = Message[0]
                    t_message.name = Message[1]
                    t_message.dlc = Message[2]
                    t_message.can_node = t_cannode
                    # t_flag = False
                    if Message[3] == self.config.local_node or t_message.id in message_id_list:
                        t_message.direction = "transmit"
                    

                    index += 1
                    try:
                        line = lines[index]
                    except:
                        break
                    MessageSearched = re.search(MessagePattern, line.strip())
                    SignalSearched = re.search(SignalPattern, line.strip())
                    if not MessageSearched:
                        while SignalSearched:
                            signal_line = list(SignalSearched.groups())
                            t_signal = signal()
                            # t_signal.name = signal_line[0].split(" ")[0]+'_'+str(t_count)+'_'+t_message.name+'_'+t_message.can_node
                            t_signal.name = signal_line[0].split(" ")[0]
                            t_signal.start_bit = int(signal_line[1])
                            t_signal.len = signal_line[2]
                            t_signal.endian = 'BIG_ENDIAN' if signal_line[3] == '0' else 'LITTLE_ENDIAN' if signal_line[3] == '1' else 'unknown'
                            t_signal.signal_type = 'uint' if signal_line[4] == '+' else 'sint' if signal_line[4] == '-' else 'unknown'
                            t_signal.factor = signal_line[5]
                            t_signal.offset = signal_line[6]
                            t_signal.min = signal_line[7]
                            t_signal.max = signal_line[8]
                            
                            if int(t_signal.len) <= 8:
                                t_signal.signal_type += '8'
                            elif int(t_signal.len) <= 16:
                                t_signal.signal_type += '16'
                            elif int(t_signal.len) <= 32:
                                t_signal.signal_type += '32'
                            elif int(t_signal.len) <= 64:
                                t_signal.signal_type += '64'
                            else:
                                logging.error("Invalid signal Type!")

                            t_message.signals.append(t_signal)
                            if signal_line[-1].find(self.config.local_node) >= 0:
                                t_message.direction = "receive"
                            
                            
                            # 再次解析信号，直到这个message下的信号全部解析完毕
                            index += 1
                            try:
                                line = lines[index]
                            except:
                                break
                            SignalSearched = re.search(SignalPattern, line.strip())



                    if t_message.direction != '':
                        self.data.append(t_message)
                else:
                    index += 1
                    try:
                        line = lines[index]
                    except:
                        break
                    MessageSearched = re.search(MessagePattern, line.strip())
    

                
    def parse_dbcs(self, dbc_path, logging):
        self.parse_config()
        self.files = self.find_dbc_files(dbc_path)
        self.read_dbcs(self.files, logging)